/*
 * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.matezk.dms.things.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.matezk.dms.common.context.UserContextHolder;
import cn.matezk.dms.common.util.StringUtils;
import cn.matezk.dms.things.mapper.DeviceMapper;
import cn.matezk.dms.things.mapper.EventMapper;
import cn.matezk.dms.things.model.entity.DeviceDO;
import cn.matezk.dms.things.model.entity.EventDO;
import cn.matezk.dms.things.model.query.EventQuery;
import cn.matezk.dms.things.model.resp.EventResp;
import cn.matezk.dms.things.service.EventService;
import cn.matezk.dms.system.enums.NotifyMethodEnum;
import cn.matezk.dms.system.mapper.UserMapper;
import cn.matezk.dms.system.model.entity.TemplateDO;
import cn.matezk.dms.system.service.TemplateService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.WxMpTemplateData;
import me.chanjar.weixin.mp.bean.WxMpTemplateMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.continew.starter.extension.crud.model.query.PageQuery;
import top.continew.starter.extension.crud.model.resp.PageResp;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

/**
 * 设备事件业务实现
 *
 * @author 程道林
 * @since 2025/01/06 17:46
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class EventServiceImpl implements EventService {

    private final EventMapper baseMapper;
    private final DeviceMapper deviceMapper;
    private final UserMapper userMapper;
    @Autowired
    private TemplateService templateService;
    @Autowired
    private WxMpService wxMpService;

    @Override
    public void handle(EventDO event) {
        DeviceDO device = deviceMapper.selectByDeviceId(event.getDeviceId());
        if (ObjectUtil.isNull(device))
            return;
        TemplateDO template = templateService.selectByEventMethod(event.getEventId(), NotifyMethodEnum.WECHAT
            .getValue());
        if (ObjectUtil.isNull(template))
            return;
        // 查询需要推送的用户
        List<String> openids = userMapper.matchWechatUser(device.getId());
        if (ObjectUtil.isNotEmpty(openids)) {
            String variable = template.getParams();
            String url = template.getUrl();
            String content = template.getContent();
            JSONObject params = event.getParams();
            params.set("aliasName", device.getAliasName());
            params.set("dataTime", DateUtil.format(event.getEventTime(), DatePattern.NORM_DATETIME_PATTERN));
            params.set("deviceName", device.getDeviceName());
            for (String key : params.keySet()) {
                variable = variable.replace(StringUtils.createVariable(key), params.getStr(key));
                content = content.replace(StringUtils.createVariable(key), params.getStr(key));
                url = url.replace(StringUtils.createVariable(key), params.getStr(key));
            }
            JSONObject pushParams = JSONUtil.parseObj(variable);
            List<WxMpTemplateData> datas = new ArrayList<>();
            for (String key : pushParams.keySet()) {
                datas.add(new WxMpTemplateData(key, pushParams.getStr(key)));
            }
            for (String openid : openids) {
                WxMpTemplateMessage message = new WxMpTemplateMessage();
                message.setToUser(openid);
                message.setTemplateId(template.getTemplateCode());
                message.setDatas(datas);
                message.setUrl(url);
                try {
                    wxMpService.templateSend(message);
                } catch (WxErrorException e) {
                    log.error("微信模板消息推送失败:{}", e.getMessage(), e);
                }
            }
        }
    }

    @Override
    public PageResp<EventResp> page(EventQuery query, PageQuery pageQuery) {
        QueryWrapper<EventDO> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotEmpty(query.getDeviceId()))
            queryWrapper.eq("e.device_id", query.getDeviceId());
        if (ObjectUtil.isNotEmpty(query.getEventTime())) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(CollUtil.getLast(query.getEventTime()));
            calendar.add(Calendar.DATE, 1);
            queryWrapper.between("e.event_time", CollUtil.getFirst(query.getEventTime()), calendar.getTime());
        }
        if (ObjectUtil.isNotEmpty(query.getEventId()))
            queryWrapper.eq("e.event_id", query.getEventId());
        if (ObjectUtil.isNull(query.getDeviceId())) {
            if (ObjectUtil.isNull(query.getDeptId())) {
                query.setDeptId(UserContextHolder.getContext().getDeptId());
            }
            queryWrapper.and(wrapper -> wrapper.apply("find_in_set({0}, dp.ancestors)", query.getDeptId())
                .or()
                .eq("d.dept_id", query.getDeptId()));
        }
        if (ObjectUtil.isNotEmpty(query.getKey())) {
            queryWrapper.and(wrapper -> wrapper.like("d.device_id", query.getKey())
                .or()
                .like("d.alias_name", query.getKey()));
        }
        queryWrapper.orderByDesc("e.event_time");
        IPage<EventResp> page = baseMapper.selectPage(new Page<>(pageQuery.getPage(), pageQuery
            .getSize()), queryWrapper);
        PageResp<EventResp> pageResp = PageResp.build(page, EventResp.class);
        return pageResp;
    }
}